#ifndef __LOOPER_HPP__

#define __LOOPER_HPP__

/*异步工作器,管理两个缓冲区及一个消费者线程*/

#include "buffer.hpp"
#include <thread>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <functional>
#include <iostream>

namespace Log
{

    enum class WorkType
    {
        SAFETY,  // 安全模式,平时运行时采用,也是末日值
        UNSAFETY // 非安全模式,测试性能用
    };

    class AsyncLooper
    {
    public:
        using fun_t = std::function<void(Buffer &)>;

    private:
        WorkType _work_mode;            // 工作模式
        Buffer _pro_buf;                   // 生产缓冲区
        Buffer _con_buf;                   // 消费者缓冲区
        std::mutex _mutex;                 // 锁
        std::condition_variable _cond_pro; // 条件不满足阻塞消费线程,由生产者唤醒
        std::condition_variable _cond_con; // 条件不满足阻塞生产线程,由消费者唤醒
        std::atomic<bool> _running;        // 保证stop修改时消费者线程立马可见
        fun_t _call_back;                  // 回调函数,外部传进来,指导怎么处理数据
        std::thread _thread;

    public:
        AsyncLooper(const fun_t &cb) : _work_mode(WorkType::SAFETY), _running(true), _call_back(cb), _thread(std::bind(&AsyncLooper::wook_loop, this)) {}
        void stop()
        {
            _running = false;
            _cond_con.notify_all(); // 唤醒消费者消费剩余数据
            _thread.join();         // 等待线程
        }
        ~AsyncLooper()
        {
            stop();
        }
        void push(const char *date, size_t len)
        {
            if (_running == false)
                return;
            // 保证在写入数据时不会交换缓冲区
            {
                std::unique_lock<std::mutex> lock(_mutex);
                // 同时被消费者通知且满足有足够空间可写才唤醒,否则继续沉睡
                if (_work_mode == WorkType::SAFETY)
                    _cond_pro.wait(lock, [&]
                                   { return _pro_buf.writeAbleSize() >= len; });
                _pro_buf.push(date, len);
            }
            _cond_con.notify_all(); // 通知消费者进行消费
        }
        void workMode(WorkType mode)
        {
            _work_mode = mode;
        }

    private:
        void wook_loop()
        {
            while (1)
            {
                // 走到这里消费者缓冲区一定是空的
                if (_running == false && _pro_buf.empty())
                    return;
                {
                    std::unique_lock<std::mutex> lock(_mutex);
                    /*以下原因基于虚假唤醒*/
                    // 当生产者缓冲区为空时没有必要交换
                    // 加运行状态防止外部调用stop时生产者数据一直为空导致线程一直阻塞在这里无法结束
                    _cond_con.wait(lock, [&]
                                   { return _pro_buf.empty() == false || _running == false; });
                }
                if (_work_mode == WorkType::SAFETY) // 安全模式下才需唤醒
                    _cond_pro.notify_all();
                _con_buf.swap(_pro_buf);
                _call_back(_con_buf);
                _con_buf.reset();
            }
        }
    };

} // namespace Log

#endif // !__LOOPER_HPP__